#ifndef MAINAPP_H
#define MAINAPP_H

#include <QMainWindow>
#include "World.h"

/// @namespace Ui the Ui namespace created from the MainWindow class
namespace Ui
{
    class MainWindow;
}

/// @file MainApp.h
/// @brief represents the main gui application window, modified from JMacey's demo
/// @author Perseedoss Rajiv
/// @version 1.0
/// @date 29.03.11
/// Revision History :
/// Initial Version 29.03.11
/// @class MainApp
/// @brief contains all the UI extended from MainWindow.ui and our GLWindowow

class MainApp : public QMainWindow
{
Q_OBJECT

public:
    /// @brief ctor
    /// @param[in] _parent the main application window for the GUI
    MainApp(
            QWidget* _parent = 0
            );

    /// @brief dtor
    ~MainApp();


private:
    /// @brief the handle to the main GUI window, used for creating all the UI and the gl window
    Ui::MainWindow* m_ui;

    /// @brief the main gl context that is used for drawing and creation of the flocking simulation
    World* m_world;

private:
    /// @brief toggle the soft limit slider based on whether hard limiting radiobutton is enabled
    /// @param [in] _state the flag to determine whether the soft limit slider should be enabled
    void setSliderWallSsoftWeightState(const bool _state);

    /// @brief convert a value from the simulation to that on the slider, given the range
    /// @param [in] _lowerTrue the lower value from the simulation
    /// @param [in] _lowerSlider the lower value of the slider
    /// @param [in] _lowerX the value from the simulation to convert
    int toSliderValue
            (
                const float _lowerTrue,
                const int _lowerSlider,
                const float _lowerX
            );

    /// @brief convert a value on the slider to the simulation, given the range
    /// @param [in] _lowerTrue the lower value from the simulation
    /// @param [in] _lowerSlider the lower value of the slider
    /// @param [in] _lowerX the value from the slider to convert
    float fromSliderValue
            (
                const float _lowerTrue,
                const int _lowerSlider,
                const int _lowerX
            );

    /// @brief toggle the color spinners, based on whether random colour check box is enabled
    /// @param [in] _state the flag to determine whether color spinners should be enabled
    void setBoiColorSpinnerEnablement(const bool _state);

    /// @brief setup up the UI intial values and connects signals/slots
    void setupConnections();


    /// @brief override the keyPressEvent inherited from QObject so we can handle key presses.
    /// @param [in] _event the event to process
    void keyPressEvent(
                       QKeyEvent* _event
                      );



private slots:
    /// @brief called when the fov neighbouring angle slider is changed
    /// @param [in] _value the changed value of the fov angle
    void on_sld_neighbouring_fov_angle_valueChanged(const int _value);

    /// @brief called when fov neighbouring policy is toggled
    /// @param [in] _checked the flag to determine whether fov neighbouring policy is enabled
    void on_fov_GroupBox_clicked(const bool _checked);

    /// @brief called from a radio button click to toggle the wall limiting type
    /// @param [in] _checked whether hard limiting of wall is enabled
    void on_rdo_wall_limiting_hard_toggled(const bool _checked);

    /// @brief called from neighbour threshold slider to update neighbouring distance in flock manager
    /// @param [in] _value the changed value for the distance
    void on_sld_boid_neighbouringThreshold_valueChanged(const int _value);

    /// @brief called to toggle thew automatic movement of the flock
    void on_cmd_autoFlock_clicked();

    /// @brief called when the boid's maximum speed slider is changed
    /// @param [in] _value the changed value of the maximum speed
    void on_sld_boid_speed_max_valueChanged(const int _value);

    /// @brief called when the boid's maximum speed slider is changed
    /// @param [in] _value the changed value of the minimum speed
    void on_sld_boid_speed_min_valueChanged(const int _value);

    /// @brief called when the shader combo box selection is changed
    /// @param [in] _index the changed value of the boid's shader
    void on_cmb_boid_shader_currentIndexChanged(const int _index);

    /// @brief called when the blue color spinner value is changed
    /// @param [in] _val the changed value for the boid's blue color channel
    void on_dspin_boid_color_b_valueChanged(const double _val);

    /// @brief called when the green color spinner value is changed
    /// @param [in] _val the changed value for the boid's green color channel
    void on_dspin_boid_color_g_valueChanged(const double _val);

    /// @brief called when the red color spinner value is changed
    /// @param [in] _val the changed value for the boid's red color channel
    void on_dspin_boid_color_r_valueChanged(const double _val);

    /// @brief called to toggle the enablement of boid's randomised colours
    /// @param [in] _checked the flag to determine whether boids' colours are assigned randomly
    void on_chk_boid_color_random_toggled(const bool _checked);

    /// @brief called when the boid scale slider is changed
    /// @param [in] _value the changed value for the boid's scale
    void on_sld_boid_scale_valueChanged(const int _value);

    /// @brief called to toggle the drawing of the bounding sphere of the boid
    /// @param [in] _checked the flag to determine whether drawing of bounding sphere is enabled
    void on_chk_boid_drawBoundingSphere_clicked(const bool _checked);

    /// @brief called to toggle the wireframe drawing of the boid
    /// @param [in] _checked the flag to determine whether wireframe drawing is enabled
    void on_chk_boid_model_wireframe_clicked(const bool _checked);

    /// @brief called when the boid model combo box selection is changed
    /// @param [in] _index the selected model of the boid
    void on_cmb_boid_model_currentIndexChanged(const int _index);

    /// @brief called when wall soft weight slider is changed
    /// @param [in] _value the changed value of the soft weight
    void on_sld_wall_soft_weight_valueChanged(const int _value);

    /// @brief called when the wall z dimension spinner is changed
    /// @param [in] _val the changed z dimension value of the wall
    void on_spin_wall_dimensions_z_valueChanged(const int _val);

    /// @brief called when the wall y dimension spinner is changed
    /// @param [in] _val the changed y dimension value of the wall
    void on_spin_wall_dimensions_y_valueChanged(const int _val);

    /// @brief called when the wall x dimension spinner is changed
    /// @param [in] _val the changed x dimension value of the wall
    void on_spin_wall_dimensions_x_valueChanged(const int _val);

    /// @brief called when wall enabled is toggled
    /// @param [in] _checked the flag to determine whether wall is enabled
    void on_wall_GroupBox_clicked(const bool _checked);

    /// @brief called when the external force z is changed
    /// @param [in] _val the changed z value of the external force
    void on_dspin_rules_externalForce_force_z_valueChanged(const double _val);

    /// @brief called when the external force y is changed
    /// @param [in] _val the changed y value of the external force
    void on_dspin_rules_externalForce_force_y_valueChanged(const double _val);

    /// @brief called when the external force x is changed
    /// @param [in] _val the changed x value of the external force
    void on_dspin_rules_externalForce_force_x_valueChanged(const double _val);

    /// @brief called when the tend towards position z is changed
    /// @param [in] _val the changed z value of the tend towards position
    void on_dspin_rules_tendTowards_position_z_valueChanged(const double _val);

    /// @brief called when the tend towards position y is changed
    /// @param [in] _val the changed y value of the tend towards position
    void on_dspin_rules_tendTowards_position_y_valueChanged(const double _val);

    /// @brief called when the tend towards position x is changed
    /// @param [in] _val the changed x value of the tend towards position
    void on_dspin_rules_tendTowards_position_x_valueChanged(const double _val);

    /// @brief called when the obstacle avoidance weight slider is changed
    /// @param [in] _value the changed value of the avoidance weight
    void on_sld_rules_obstacleAvoidance_weight_valueChanged(const int _value);

    /// @brief called when the external force weight slider is changed
    /// @param [in] _value the changed value of the external force weight
    void on_sld_rules_externalForce_weight_valueChanged(const int _value);

    /// @brief called when the tend toward weight slider is changed
    /// @param [in] _value the changed value of the tend toward weight
    void on_sld_rules_tendTowards_weight_valueChanged(const int _value);

    /// @brief called when the alignment weight slider is changed
    /// @param [in] _value the changed value of the alignment weight
    void on_sld_rules_alignment_weight_valueChanged(const int _value);

    /// @brief called when the separation minimum distance slider is changed
    /// @param [in] _value the changed value of the separation distance
    void on_sld_rules_separation_threshold_valueChanged(const int _value);

    /// @brief called when the separation weight slider is changed
    /// @param [in] _value the changed value of the separation weight
    void on_sld_rules_separation_weight_valueChanged(const int _value);

    /// @brief called when the cohesion weight slider is changed
    /// @param [in] _value the changed value of the cohesion weight
    void on_sld_rules_cohesion_weight_valueChanged(const int _value);

    /// @brief called to toggle the enablement of obstacle avoidance
    /// @param [in] _checked the flag to determine whether avoidance is enabled
    void on_obstacleAvoidance_GroupBox_clicked(const bool _checked);

    /// @brief called to toggle the drawing of the influence sphere of obstacles
    /// @param [in] _checked the flag to determine whether to draw the influence sphere of obstacles
    void on_chk_rules_obstacle_drawInfluenceSphere_clicked(const bool _checked);

    /// @brief called to toggle the wireframe drawing of obstacles
    /// @param [in] _checked the flag to determine whether to wireframe drawing of obstacles
    void on_chk_rules_obstacle_wireframe_clicked(const bool _checked);

    /// @brief called to toggle the enablement of obstacles in the simulation
    /// @param [in] _checked the flag to determine whether obstacles are enabled
    void on_obstacle_GroupBox_clicked(const bool _checked);

    /// @brief called to toggle the enablement of external force
    /// @param [in] _checked the flag to determine whether external force is enabled
    void on_externalForce_GroupBox_clicked(const bool _checked);

    /// @brief called to toggle the enablement of tend toward rule
    /// @param [in] _checked the flag to determine whether tend toward is enabled
    void on_tendToward_GroupBox_clicked(const bool _checked);

    /// @brief called to toggle the enablement of alignment
    /// @param [in] _checked the flag to determine whether alignment is enabled
    void on_alignment_GroupBox_clicked(const bool _checked);

    /// @brief called to toggle the enablement of separation
    /// @param [in] _checked the flag to determine whether separation is enabled
    void on_separation_GroupBox_clicked(const bool _checked);

    /// @brief called to toggle the enablement of cohesion
    /// @param [in] _checked the flag to determine whether cohesion is enabled
    void on_cohesion_GroupBox_clicked(const bool _checked);

    /// @brief called to toggle the enablement of normalisation of velocities
    /// @param [in] _checked the flag to determine whether velocities are normalised
    void on_chk_rules_normaliseVelocities_clicked(const bool _checked);

    /// @brief called when the boid under neighbour tracing is changed
    /// @param [in] _value the boid number whose neighbours are traced
    void on_spin_flock_traceBoidAndNeighbours_boidNo_valueChanged(const int _value);

    /// @brief called to toggle the tracing of boids and their neighbours
    /// @param [in] _checked the flag to determine whether neighbour tracing is enabled
    void on_traceBoidAndNeighbour_GroupBox_clicked(const bool _checked);

    /// @brief called to re intialise the flock and its boids
    void on_cmd_refreshSimulation_clicked();

    /// @brief called to move the flock one step forward
    void on_cmd_singleStep_clicked();

    /// @brief called to add a boid to the current flock
    void on_cmd_addBoid_clicked();


};

#endif // MAINAPP_H
